package com.cs.framework.jdbc.mybatis3.executor.resultset;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.ObjectTypeHandler;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.apache.ibatis.type.UnknownTypeHandler;

/**
 * 查询结果包装类
 * 
 * @author hedongzhou
 * 
 */
public class ResultSetWrapper {

	private ResultSet resultSet;

	private TypeHandlerRegistry typeHandlerRegistry;

	private List<String> columnNames = new ArrayList<String>();

	private List<String> classNames = new ArrayList<String>();

	private List<JdbcType> jdbcTypes = new ArrayList<JdbcType>();

	private Map<String, Map<Class<?>, TypeHandler<?>>> typeHandlerMap = new HashMap<String, Map<Class<?>, TypeHandler<?>>>();

	private Map<String, List<String>> unMappedColumnNamesMap = new HashMap<String, List<String>>();

	public ResultSetWrapper(ResultSet rs, Configuration configuration) throws SQLException {
		this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
		this.resultSet = rs;
		final ResultSetMetaData metaData = rs.getMetaData();
		final int columnCount = metaData.getColumnCount();
		for (int i = 1; i <= columnCount; i++) {
			columnNames.add(configuration.isUseColumnLabel() ? metaData.getColumnLabel(i) : metaData.getColumnName(i));
			jdbcTypes.add(JdbcType.forCode(metaData.getColumnType(i)));
			classNames.add(metaData.getColumnClassName(i));
		}
	}

	public ResultSet getResultSet() {
		return resultSet;
	}

	public List<String> getColumnNames() {
		return this.columnNames;
	}

	public TypeHandler<?> getTypeHandler(Class<?> propertyType, String columnName) throws ClassNotFoundException {
		TypeHandler<?> handler = null;
		Map<Class<?>, TypeHandler<?>> columnHandlers = typeHandlerMap.get(columnName);
		if (columnHandlers == null) {
			columnHandlers = new HashMap<Class<?>, TypeHandler<?>>();
			typeHandlerMap.put(columnName, columnHandlers);
		} else {
			handler = columnHandlers.get(propertyType);
		}
		if (handler == null) {
			handler = typeHandlerRegistry.getTypeHandler(propertyType);
			if (handler == null || handler instanceof UnknownTypeHandler) {
				int index = columnNames.indexOf(columnName);
				JdbcType jdbcType = jdbcTypes.get(index);
				Class<?> javaType = Resources.classForName(classNames.get(index));
				if (javaType != null && jdbcType != null) {
					handler = typeHandlerRegistry.getTypeHandler(javaType, jdbcType);
				} else if (javaType != null) {
					handler = typeHandlerRegistry.getTypeHandler(javaType);
				} else if (jdbcType != null) {
					handler = typeHandlerRegistry.getTypeHandler(jdbcType);
				}
			}
			if (handler == null || handler instanceof UnknownTypeHandler) {
				handler = new ObjectTypeHandler();
			}
			columnHandlers.put(propertyType, handler);
		}
		return handler;
	}

	public List<String> getUnmappedColumnNames(String id) throws SQLException {
		loadMappedAndUnmappedColumnNames(id);
		List<String> unMappedColumnNames = unMappedColumnNamesMap.get(id);
		return unMappedColumnNames;
	}

	private void loadMappedAndUnmappedColumnNames(String id) throws SQLException {
		List<String> unmappedColumnNames = new ArrayList<String>();
		for (String columnName : columnNames) {
			unmappedColumnNames.add(columnName);
		}
		unMappedColumnNamesMap.put(id, unmappedColumnNames);
	}

}
